#pragma once
#ifndef _LINAL_VECTOR_
#define _LINAL_VECTOR_

//================================================================================================================================
//================================================================================================================================
// QtCore
#include <QtCore/QVector>
// Локальные
#include "core_global.h"

//================================================================================================================================
//================================================================================================================================
namespace linal
{
    /// Вектор в вещественном n-мерном пространстве.
    class CORE_EXPORT Vector
    {
    public:
        /// Создание вектора нулевой длины (размерности 0).
        Vector() : m_Vector(0) {}

        /// Создание нулевого вектора длины \e size.
        explicit Vector(int size) : m_Vector(size, 0.) {}

        /// Создание ветора размерности \e size.
        /// \param size Размерность создаваемого вектора.
        /// \param value Значение, присваиваемое элементам вектора.
        Vector(int size, double value) : m_Vector(size, value) {}

        /// Создание вектора на основе сохраненных в файле данных.
        //
        /// Предполагается, что файл содержит информацию о решение конечноэлементной задачи и имеет структуру
        /// <координата r><координата z><значение функции в точке (r;z)>. В вектор сохраняются только значения функции.
        /// \param filename Имя файла с данными о ввекторе.
        Vector(const QString &filename);

        /// Получение размерности вектора.
        int dimension() const {return m_Vector.size();}

        /// Изменение размерность вектора.
        /// \param size Новая размерность вектора.
        void resize(int size) {m_Vector.resize(size);}

        /// Обнуление всех элементов вектора (приравнивание их к нулю).
        /// \remarks Функция создана для обнуления вектора правой перед началом сборки СЛАУ для МКЭ.
        void zeroize() {m_Vector.fill(0.);}

        /// Получение нормы вектора.
        double norm() const;

        /// Получение квадрата нормы вектора
        /// \remarks В некоторых математических алгоритмах можно использовать не норму вектора, а квадрат нормы,
        /// что дает выигрыш в быстродействии.
        double normSquared() const;

        /// Получение нормы вектора.
        static double norm(const Vector &vector);

        /// Получение квадрата нормы вектора
        /// \remarks В некоторых математических алгоритмах можно использовать не норму вектора, а квадрат нормы,
        /// что дает выигрыш в быстродействии.
        static double normSquared(const Vector &vector);

        /// Считать вектор из файла \e filename.
        //
        /// Предполагается, что файл содержит информацию о решение конечноэлементной задачи и имеет структуру
        /// <координата r><координата z><значение функции в точке (r;z)>. В вектор сохраняются только значения функции.
        void readFromFile(const QString &filename);

        /// Прибавление к данному ветору вектора \e vector.
        Vector& operator+=(const Vector &vector);

        /// Вычитание из данного ветора вектора \e vector.
        Vector& operator-=(const Vector &vector);

        /// Умножение данного вектора на скаляр \e factor.
        Vector& operator*=(double factor);

        /// Деление данного вектора на скаляр \e divisor.
        Vector& operator/=(double divisor);

        /// Получение доступа к элементам вектора.
        double& operator[](int i) {return m_Vector[i];}

        /// Перегруженная функция.
        const double& operator[](int i) const {return m_Vector[i];}

    private:
        QVector<double> m_Vector;
    };

    //============================================================================================================================
    //============================================================================================================================
    /// Скалярное умножение векторов.
    /// \relates Vector
    CORE_EXPORT double operator*(const Vector &v1, const Vector &v2);

    /// Сложение векторов.
    /// \relates Vector
    CORE_EXPORT const Vector operator+(const Vector &v1, const Vector &v2);

    /// Вычитание векторов.
    /// \relates Vector
    CORE_EXPORT const Vector operator-(const Vector &v1, const Vector &v2);

    /// Умножение вектора на скаляр.
    /// \relates Vector
    CORE_EXPORT const Vector operator*(double factor, const Vector &vector);

    /// Умножение вектора на скаляр.
    /// \relates Vector
    CORE_EXPORT const Vector operator*(const Vector &vector, double factor);

    /// Деление вектора на скаляр.
    /// \relates Vector
    CORE_EXPORT const Vector operator/(const Vector &vector, double divisor);

    /// Получение вектора противоположному данному.
    /// \relates Vector
    CORE_EXPORT const Vector operator-(const Vector &vector);
}

#endif // VECTOR_H
